package factory.one.service;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;

@Service
public class OrderSequenceService {

    private final JdbcTemplate jdbcTemplate;

    public OrderSequenceService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public synchronized String nextCode() {
        LocalDate current = LocalDate.now();
        int year = current.getYear();
        int month = current.getMonthValue();
        int day = current.getDayOfMonth();
        long id = year * 10000L + month * 100 + day;

        int updateRow = increase(id);
        if (updateRow == 0) {
            add(id, 1L);
            return format(year, month, day, 1L);
        } else {
            return format(year, month, day, getById(id));
        }
    }

    private int add(Long id, Long value) {
        return jdbcTemplate.update("insert into ORDERSEQUENCE(id,value) values(?,?)", id, value);
    }

    private int increase(Long id) {
        return jdbcTemplate.update("update ORDERSEQUENCE set value = value + 1 where id = ?", id);
    }

    private Long getById(Long id) {
        return jdbcTemplate.query("select value from ORDERSEQUENCE where id = " + id, new ResultSetExtractor<Long>() {
            @Override
            public Long extractData(ResultSet rs) throws SQLException, DataAccessException {
                if (rs.next()) {
                    return rs.getLong(1);
                }
                return null;
            }
        });
    }

    private String format(int year, int month, int day, long sequence) {
        StringBuilder result = new StringBuilder();
        result.append(year - 2000);
        result.append(transMonth(month));
        if (day > 9) {
            result.append(day);
        } else {
            result.append(0).append(day);
        }
        result.append("-");
        if (sequence > 9) {
            result.append(sequence);
        } else {
            result.append(0).append(sequence);
        }
        return result.toString();
    }

    private String transMonth(int month) {
        switch (month) {
            case 10:
                return "O";
            case 11:
                return "N";
            case 12:
                return "D";
            default:
                return Integer.toString(month);
        }
    }

    private long curDateInLong() {
        LocalDate current = LocalDate.now();
        return current.getYear() * 10000L + current.getMonthValue() * 100 + current.getDayOfMonth();
    }

}
